package ace.tool.generate.code.impl.manager;

import ace.tool.generate.code.impl.generator.DefaultGenerator;
import ace.tool.generate.code.impl.manager.common.EntityModelManager;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.GenerateContext;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.api.ApiClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.api.DtoClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.core.EntityClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.FeignApiClassInfo;
import ace.tool.generate.code.impl.resolver.scheme.model.bo.sdk.FeignClassInfo;
import java.util.HashMap;
import java.util.Map;
import lombok.SneakyThrows;

/**
 * @author caspar
 * @date 2024/1/11 10:12 api project generator
 */
public class SdkProjectManager {

  private final GenerateContext context;

  public SdkProjectManager(GenerateContext context) {
    this.context = context;
  }

  @SneakyThrows
  public void generate() {

    this.generatePom();

    this.generateReadme();

    this.generateResourcesSpringFactories();

    this.generateResourcesAutoConfigurationImports();

    this.generateSdkAutoConfigClass();

    this.generateConstant();

    this.generateFeignApis();

    this.generateFeigns();

    this.generateFeignScanner();

  }

  private void generateConstant() {
    Map<String, Object> model = new HashMap<>();
    model.put(
        "packageFullName",
        context
            .getModuleProject()
            .getSdkProject()
            .getConstantClassInfo()
            .getInfo()
            .getClassPackageFullName());
    model.put(
        "className",
        context
            .getModuleProject()
            .getSdkProject()
            .getConstantClassInfo()
            .getInfo()
            .getClassName());

    model.put(
        "feignServiceName",
        context
            .getModuleProject()
            .getSdkProject()
            .getConstantClassInfo()
            .getFeignServiceName());

    String templateFile = "/schema/sdk-project/SdkProjectConstantClass.ftl";
    String outputFileFullName =
        context
            .getModuleProject()
            .getSdkProject()
            .getConstantClassInfo()
            .getInfo()
            .getClassFileFullName();
    new DefaultGenerator(templateFile, outputFileFullName).generate(model);
  }

  private void generateFeignScanner() {
    Map<String, Object> model = new HashMap<>();
    model.put(
        "packageFullName",
        context
            .getModuleProject()
            .getSdkProject()
            .getFeignScannerClassInfo()
            .getInfo()
            .getClassPackageFullName());
    model.put(
        "className",
        context
            .getModuleProject()
            .getSdkProject()
            .getFeignScannerClassInfo()
            .getInfo()
            .getClassName());
    String templateFile = "/schema/sdk-project/SdkProjectFeignScannerClass.ftl";
    String outputFileFullName =
        context
            .getModuleProject()
            .getSdkProject()
            .getFeignScannerClassInfo()
            .getInfo()
            .getClassFileFullName();
    new DefaultGenerator(templateFile, outputFileFullName).generate(model);
  }

  private void generateFeigns() {
    context.getModuleProject().getSdkProject().getFeignClassInfos().forEach(this::generateFeign);
  }

  private void generateFeign(FeignClassInfo feignClassInfo) {
    EntityModelManager entityModelManager = new EntityModelManager();
    EntityClassInfo entityClassInfo =
        entityModelManager.getEntityClassInfoByEntityModelId(
            context, feignClassInfo.getEntityModelId());
    FeignApiClassInfo feignApiClassInfo =
        entityModelManager.getFeignApiClassInfoByEntityModelId(
            context, feignClassInfo.getEntityModelId());
    Map<String, Object> model = new HashMap<>();
    model.put("packageFullName", feignClassInfo.getInfo().getClassPackageFullName());
    model.put("feignApiClassFullName", feignApiClassInfo.getInfo().getClassFullName());
    model.put("remark", entityClassInfo.getModel().getRemark());
    model.put("feignClientConfigPrefix", feignClassInfo.getFeignClientConfigPrefix());
    model.put("feignFirstLowercaseClassName", feignClassInfo.getFeignFirstLowercaseClassName());
    model.put("className", feignClassInfo.getInfo().getClassName());
    model.put("feignApiClassName", feignApiClassInfo.getInfo().getClassName());
    model.put("restNamespace", feignClassInfo.getRestNamespace());
    model.put(
        "entityClassNameLowercaseDashName", feignClassInfo.getEntityClassNameLowercaseDashName());
    model.put("sdkConstantClassName",
        context.getModuleProject().getSdkProject().getConstantClassInfo().getInfo().getClassName());
    model.put("sdkConstantClassFullName",
        context.getModuleProject().getSdkProject().getConstantClassInfo().getInfo()
            .getClassFullName());
    model.put("sdkConstantFeignServicePropertyName",
        context.getModuleProject().getSdkProject().getConstantClassInfo().getInfo().getClassName()
            + ".FEIGN_SERVICE_NAME");
    String templateFile = "/schema/sdk-project/SdkProjectFeignClass.ftl";
    String outputFileFullName = feignClassInfo.getInfo().getClassFileFullName();
    new DefaultGenerator(templateFile, outputFileFullName).generate(model);
  }

  private void generateFeignApis() {
    context
        .getModuleProject()
        .getSdkProject()
        .getFeignApiClassInfos()
        .forEach(this::generateFeignApi);
  }

  private void generateFeignApi(FeignApiClassInfo feignApiClassInfo) {
    EntityModelManager entityModelManager = new EntityModelManager();
    EntityClassInfo entityClassInfo =
        entityModelManager.getEntityClassInfoByEntityModelId(
            context, feignApiClassInfo.getEntityModelId());
    DtoClassInfo dtoClassInfo =
        entityModelManager.getDtoClassInfoByEntityModelId(
            context, feignApiClassInfo.getEntityModelId());
    ApiClassInfo apiClassInfo =
        entityModelManager.getApiClassInfoByEntityModelId(
            context, feignApiClassInfo.getEntityModelId());
    Map<String, Object> model = new HashMap<>();
    model.put("packageFullName", feignApiClassInfo.getInfo().getClassPackageFullName());
    model.put("dtoClassFullName", dtoClassInfo.getInfo().getClassFullName());
    model.put("apiClassFullName", apiClassInfo.getInfo().getClassFullName());
    model.put("className", feignApiClassInfo.getInfo().getClassName());
    model.put("remark", entityClassInfo.getModel().getRemark());
    model.put("dtoClassName", dtoClassInfo.getInfo().getClassName());
    model.put("apiClassName", apiClassInfo.getInfo().getClassName());
    model.put("entityIdType", entityClassInfo.getModel().getEntityIdType());
    String templateFile = "/schema/sdk-project/SdkProjectFeignApiClass.ftl";
    String outputFileFullName = feignApiClassInfo.getInfo().getClassFileFullName();
    new DefaultGenerator(templateFile, outputFileFullName).generate(model);
  }

  private void generateSdkAutoConfigClass() {
    Map<String, Object> model = new HashMap<>();
    model.put(
        "packageFullName",
        context
            .getModuleProject()
            .getSdkProject()
            .getSdkAutoConfigClassInfo()
            .getInfo()
            .getClassPackageFullName());
    model.put(
        "sdkFeignScannerClassFullName",
        context
            .getModuleProject()
            .getSdkProject()
            .getFeignScannerClassInfo()
            .getInfo()
            .getClassFullName());
    model.put(
        "sdkFeignScannerClassName",
        context
            .getModuleProject()
            .getSdkProject()
            .getFeignScannerClassInfo()
            .getInfo()
            .getClassName());
    model.put(
        "className",
        context
            .getModuleProject()
            .getSdkProject()
            .getSdkAutoConfigClassInfo()
            .getInfo()
            .getClassName());
    String templateFile = "/schema/sdk-project/SdkProjectAutoConfigClass.ftl";
    String outputFileFullName =
        context
            .getModuleProject()
            .getSdkProject()
            .getSdkAutoConfigClassInfo()
            .getInfo()
            .getClassFileFullName();
    new DefaultGenerator(templateFile, outputFileFullName).generate(model);
  }

  private void generateResourcesAutoConfigurationImports() {
    Map<String, Object> model = new HashMap<>();
    model.put(
        "classFullNames",
        context
            .getModuleProject()
            .getSdkProject()
            .getAutoConfigurationImportsFileInfo()
            .getClassFullNameImports());
    String templateFile = "/schema/sdk-project/SdkProjectAutoConfigurationImports.ftl";
    String outputFileFullName =
        context
            .getModuleProject()
            .getSdkProject()
            .getAutoConfigurationImportsFileInfo()
            .getFileFullName();
    new DefaultGenerator(templateFile, outputFileFullName).generate(model);
  }

  private void generateResourcesSpringFactories() {
    Map<String, Object> model = new HashMap<>();
    model.put(
        "classFullNames",
        context
            .getModuleProject()
            .getSdkProject()
            .getSpringFactoriesFileInfo()
            .getClassFullNameImports());
    String templateFile = "/schema/sdk-project/SdkProjectSpringFactories.ftl";
    String outputFileFullName =
        context.getModuleProject().getSdkProject().getSpringFactoriesFileInfo().getFileFullName();
    new DefaultGenerator(templateFile, outputFileFullName).generate(model);
  }

  private void generateReadme() {
    Map<String, String> model = new HashMap<>();
    String templateFile = "/schema/sdk-project/SdkProjectReadme.ftl";
    String outputFileFullName =
        context.getModuleProject().getSdkProject().getInfo().getReadmeFileFullName();
    new DefaultGenerator(templateFile, outputFileFullName).generate(model);
  }

  private void generatePom() {
    Map<String, String> model = new HashMap<>();
    model.put("projectMavenArtifactId", context.getModuleProject().getInfo().getMavenArtifactId());
    model.put(
        "apiProjectMavenArtifactId",
        context.getModuleProject().getApiProject().getInfo().getMavenArtifactId());
    model.put(
        "sdkProjectMavenArtifactId",
        context.getModuleProject().getSdkProject().getInfo().getMavenArtifactId());

    String templateFile = "/schema/sdk-project/SdkProjectPom.ftl";
    String outputFileFullName =
        context.getModuleProject().getSdkProject().getInfo().getPomFileFullName();
    new DefaultGenerator(templateFile, outputFileFullName).generate(model);
  }
}
